#pragma once

#include <ddblk/locks/lock_int.h>

typedef struct _ticketlock
{
	lkword_t max_ticket;
	lkword_t cur_ticket;
} _ticketlock_t;

typedef void _ticketnode_t;

DECL_LOCK(ticket)

PARAM_NONULL(1) SAI _ticketlock_t *_ticket_init(void *ptr, size_t size)
{	
	if (size < sizeof(_ticketlock_t)) return NULL;
	_ticketlock_t *s = (_ticketlock_t *)ptr;
	s->max_ticket = 0;
	s->cur_ticket = 0;
	return s;
}

PARAM_NONULL(1) SAI void *_ticket_destruct(_ticketlock_t *s)
{
	PARAM_USED(s);
	return (void *)s;
}

PARAM_NONULL(1) SAI bool_t _ticket_lock(_ticketlock_t *s, locktoken_t *ptoken, waitcnt_t cnt, 
	INFUN(lock, waitpolicy), const acq_ord_t order)
{

	lkword_t ret = faa(&s->max_ticket, 1);
	lkword_t cur = atm_ld(&s->cur_ticket);	
	while (ret != cur)
	{
		/* 等待超时 */
		cnt = waitpolicy->waitf(&s->cur_ticket, &cur, cnt);
		if (!cnt) return FALSE;

		cur = atm_ld(&s->cur_ticket);	
	}
	if (order == LACQ) mp_rmb();

	*ptoken = (locktoken_t)((paddr_t)ret);
	return TRUE;
}

PARAM_NONULL(1) SAI bool_t _ticket_unlock(_ticketlock_t *s, locktoken_t token, waitcnt_t cnt, 
	INFUN(lock, waitpolicy),  const rel_ord_t order)
{
	PARAM_USED(cnt);

	lkword_t next = (lkword_t)((paddr_t)token) + 1; // s->cur_ticket + 1;

	if (order == RREL)atm_strel(&s->cur_ticket, next);
	else atm_st(&s->cur_ticket, next);

	/* 通知等待线程 */
	waitpolicy->wakef(&s->cur_ticket, &next);

	return TRUE;
}

/* 重试次数限制 */
DEF_LOCK(ticket, bounded_ticket, OUFUN_OF(spin_wait_bounded))
/* 永远自旋 */
DEF_LOCK(ticket, ticket, OUFUN_OF(spin_wait))
/* 调度放弃 */
DEF_LOCK(ticket, yield_ticket, OUFUN_OF(schedyield_wait))
/* futex等待 */
DEF_LOCK(ticket, futex_ticket, OUFUN_OF(futex_wait))
